package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zzyl.common.core.redis.RedisCache;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.nursing.config.WebSocketServer;
import com.zzyl.nursing.domain.AlertData;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.mapper.AlertDataMapper;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IAlertDataService;
import com.zzyl.nursing.service.IDeviceService;
import com.zzyl.nursing.vo.AlertNotifyVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.AlertRuleMapper;
import com.zzyl.nursing.domain.AlertRule;
import com.zzyl.nursing.service.IAlertRuleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import java.util.concurrent.TimeUnit;

/**
 * 告警规则Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-06-12
 */
@Slf4j
@Service
public class AlertRuleServiceImpl extends ServiceImpl<AlertRuleMapper, AlertRule> implements IAlertRuleService
{
    @Autowired
    private AlertRuleMapper alertRuleMapper;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private IAlertDataService iAlertDataService;

    /**
     * 查询告警规则
     * 
     * @param id 告警规则主键
     * @return 告警规则
     */
    @Override
    public AlertRule selectAlertRuleById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询告警规则列表
     * 
     * @param alertRule 告警规则
     * @return 告警规则
     */
    @Override
    public List<AlertRule> selectAlertRuleList(AlertRule alertRule)
    {
        return alertRuleMapper.selectAlertRuleList(alertRule);
    }

    /**
     * 新增告警规则
     * 
     * @param alertRule 告警规则
     * @return 结果
     */
    @Override
    public int insertAlertRule(AlertRule alertRule)
    {
        return save(alertRule) ? 1 : 0;
    }

    /**
     * 修改告警规则
     * 
     * @param alertRule 告警规则
     * @return 结果
     */
    @Override
    public int updateAlertRule(AlertRule alertRule)
    {
        return updateById(alertRule) ? 1 : 0;
    }

    /**
     * 批量删除告警规则
     * 
     * @param ids 需要删除的告警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除告警规则信息
     * 
     * @param id 告警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleById(Long id)
    {
        return removeById(id) ? 1 : 0;
    }

    @Override
    public void deviceDataAlertJob() {
        //1.查询所有规则存不存在
        long count = this.count(Wrappers.<AlertRule>lambdaQuery().eq(AlertRule::getStatus,1));
        if(count < 1){
          return;
        }
        //2.查询所有设备上报的数据
        List<Object> values = redisTemplate.opsForHash().values("iot:product_data_latest");
        if(CollUtil.isEmpty(values)){
          return;
        }

        List<DeviceData> deviceDataList = new ArrayList<>();
        values.forEach(value->{
            List<DeviceData> list = JSONUtil.toList(value.toString(), DeviceData.class);
            deviceDataList.addAll(list);
        });

        //3.遍历所有的上报数据，去匹配规则
        deviceDataList.forEach(deviceData -> {
            alertRuleData(deviceData);
        });
    }


     //数据匹配告警规则
    private void alertRuleData(DeviceData deviceData) {
       //1.查询所有的关联设备规则
        List<AlertRule> allAlertRules = this.list(new LambdaQueryWrapper<AlertRule>()
                .eq(AlertRule::getProductKey,deviceData.getProductKey())
                .eq(AlertRule::getFunctionId,deviceData.getFunctionId())
                .eq(AlertRule::getIotId,-1)
                .eq(AlertRule::getStatus,1));

        //2.查询某个设备规则
        List<AlertRule> iotDevicealertRules = this.list(new LambdaQueryWrapper<AlertRule>()
                .eq(AlertRule::getProductKey,deviceData.getProductKey())
                .eq(AlertRule::getFunctionId,deviceData.getFunctionId())
                .eq(AlertRule::getIotId,deviceData.getIotId())
                .eq(AlertRule::getStatus,1));
        //3.所有设备数据满足的规则放一起
        allAlertRules.addAll(iotDevicealertRules);
        if(CollUtil.isEmpty(allAlertRules)){
            return;
        }

        //4.我要去用每条数据去匹配规则----遍历每条规则去匹配数据是否告警
        allAlertRules.forEach(alertRule -> {
            alertRuleMatchDeviceData(alertRule,deviceData);
        });

    }

    //遍历每条规则去匹配数据是否告警
    private void alertRuleMatchDeviceData(AlertRule alertRule, DeviceData deviceData) {
        //1.校验数据数据时候在不在生效范围
        LocalTime time = deviceData.getAlarmTime().toLocalTime();
        //00:00:00-23:59:59
        String[] split = alertRule.getAlertEffectivePeriod().split("~");
        LocalTime startTime = LocalTime.parse(split[0]);
        LocalTime endTime = LocalTime.parse(split[1]);
        if(time.isBefore(startTime) || time.isAfter(endTime)){
            return;
        }
       //2.校验数据是否达到阈值
        Double devicedataValue = Double.valueOf(deviceData.getDataValue());
        Double ruleValue = alertRule.getValue();
        //x>y =1  x=y=0, x<y =-1
        int compare = CompareUtil.compare(devicedataValue, ruleValue);
        if((alertRule.getOperator().equals(">=") && compare >= 0) || (alertRule.getOperator().equals("<") && compare < 0)){
          log.info("符合告警规则");
        }else {
            //TODO //删除redis 的报警数
            redisTemplate.delete("iot:duration:" + deviceData.getIotId() + ":" + deviceData.getFunctionId() + ":" + alertRule.getId());
            return;
        }

        //3.判断沉默周期
        String silent = redisTemplate.opsForValue().get("iot:silent:" + deviceData.getIotId() + ":" + deviceData.getFunctionId() + ":" + alertRule.getId());
        if(ObjectUtil.isNotEmpty(silent)){
            return;
        }

        //4.判断持续周期
        String count = redisTemplate.opsForValue().get("iot:duration:" + deviceData.getIotId() + ":" + deviceData.getFunctionId() + ":" + alertRule.getId());
        //redis 取次数--第一次算一次。不是就+1次
        int sum = count ==null ? 1 : Integer.valueOf(count)+1;
        if(!alertRule.getDuration().equals(sum)){
            redisTemplate.opsForValue().set("iot:duration:" + deviceData.getIotId() + ":" + deviceData.getFunctionId() + ":" + alertRule.getId(),sum+"");
            return;
        }

        //5.所有规则都满足，我是不是要去告警
        redisTemplate.delete("iot:duration:" + deviceData.getIotId() + ":" + deviceData.getFunctionId() + ":" + alertRule.getId());

        //6.添加沉默周期
       redisTemplate.opsForValue().set("iot:silent:" + deviceData.getIotId() + ":" + deviceData.getFunctionId() + ":" + alertRule.getId(),"1111",alertRule.getAlertSilentPeriod(), TimeUnit.MINUTES);

       //7.校验完成
        List<Long> userIds = null;
        if(alertRule.getAlertDataType().equals(0)){ //等于0它是老人异常数据
            if(deviceData.getLocationType().equals(0)){ //老人的随时设备---手表
               userIds = deviceMapper.selectNursingIdsByIotIdWithElder(deviceData.getIotId());
            }else {     //老人固定设备---床
               userIds = deviceMapper.selectNursingIdsByIotIdWithBed(deviceData.getIotId());
            }
        }else{ //设备异常数据
            //查询维修人员的id
             userIds =  deviceMapper.selectUserIdByRoleName("维修工");
        }
        //发送一份给超级管理员
        List<Long> managers =  deviceMapper.selectUserIdByRoleName("超级管理员");

        Collection<Long> longs = CollUtil.addAll(userIds, managers);
        List<Long> idList = CollUtil.distinct(longs);

        //告警数据和用户插入数据库，推送告警数据
        insertBatchRuleData(idList,alertRule,deviceData);

    }

    @Autowired
    private WebSocketServer webSocketServer;

    private void insertBatchRuleData(List<Long> idList, AlertRule alertRule, DeviceData deviceData) {
        AlertData alertData  = BeanUtil.toBean(deviceData,AlertData.class);
        alertData.setAlertRuleId(alertRule.getId());
        alertData.setAlertReason(alertRule.getFunctionName() + alertRule.getOperator() +alertRule.getValue()+",持续"+ alertRule.getDuration()+"个周期就报警");
        alertData.setType(alertRule.getAlertDataType());
        alertData.setStatus(0);
        alertData.setCreateTime(new Date());
        alertData.setUpdateTime(new Date());
        alertData.setAccessLocation(deviceData.getRemark());

        List<AlertData> alertDataList = new ArrayList<>();
        idList.forEach(userid->{
            AlertData data = BeanUtil.toBean(alertData, AlertData.class);
            data.setId(null);
            data.setUserId(userid);
            alertDataList.add(data);
        });

        iAlertDataService.saveBatch(alertDataList);

       //推送消息给护理员
        AlertNotifyVo alertNotifyVo = BeanUtil.toBean(alertDataList.get(0), AlertNotifyVo.class);
        alertNotifyVo.setAlertDataType(alertRule.getAlertDataType());
        alertNotifyVo.setFunctionName(alertRule.getFunctionName());
        alertNotifyVo.setNotifyType(1);
        webSocketServer.sendMessageToConsumer(alertNotifyVo,idList);
    }
}
